package com.zhentao.util;

import com.arcsoft.face.EngineConfiguration;
import com.arcsoft.face.FaceEngine;
import com.arcsoft.face.FaceInfo;
import com.arcsoft.face.FunctionConfiguration;
import com.arcsoft.face.enums.DetectMode;
import com.arcsoft.face.enums.DetectOrient;
import com.arcsoft.face.enums.ErrorInfo;
import com.arcsoft.face.toolkit.ImageInfo;
import com.arcsoft.face.toolkit.ImageInfoEx;
import com.arcsoft.face.enums.ImageFormat;
import com.arcsoft.face.FaceSimilar;
import com.zhentao.config.FaceEngineConfig;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * 虹软人脸识别工具类
 */
@Slf4j
@Component
public class FaceEngineUtil {

    @Autowired
    private FaceEngineConfig config;

    private FaceEngine faceEngine;

    /**
     * 初始化人脸引擎
     */
    @PostConstruct
    public void init() {
        try {
            // 调试：打印当前工作目录和配置的库路径
            log.info("当前工作目录: {}", System.getProperty("user.dir"));
            log.info("配置的库路径: {}", config.getLibPath());
            
            // 动态获取库路径
            String libPath = getActualLibPath();
            log.info("实际使用的库路径: {}", libPath);
            
            faceEngine = new FaceEngine(libPath);
            
            // 激活引擎（在线激活方式）
            int errorCode = faceEngine.activeOnline(config.getAppId(), config.getSdkKey());
            if (errorCode != ErrorInfo.MOK.getValue() && errorCode != ErrorInfo.MERR_ASF_ALREADY_ACTIVATED.getValue()) {
                log.error("引擎激活失败，错误码: {}", errorCode);
                throw new RuntimeException("人脸引擎激活失败");
            }
            
            // 引擎配置（参考示例代码）
            EngineConfiguration engineConfiguration = new EngineConfiguration();
            engineConfiguration.setDetectMode(DetectMode.ASF_DETECT_MODE_IMAGE);
            engineConfiguration.setDetectFaceOrientPriority(DetectOrient.ASF_OP_ALL_OUT);
            engineConfiguration.setDetectFaceMaxNum(config.getMaxFaceNum());
            engineConfiguration.setDetectFaceScaleVal(16);
            
            // 功能配置
            FunctionConfiguration functionConfiguration = new FunctionConfiguration();
            functionConfiguration.setSupportAge(true);
            functionConfiguration.setSupportGender(true);
            functionConfiguration.setSupportFace3dAngle(true);
            functionConfiguration.setSupportFaceDetect(true);
            functionConfiguration.setSupportFaceRecognition(true);
            functionConfiguration.setSupportLiveness(true);
            functionConfiguration.setSupportIRLiveness(false);
            engineConfiguration.setFunctionConfiguration(functionConfiguration);
            
            // 初始化引擎
            errorCode = faceEngine.init(engineConfiguration);
                    
            if (errorCode != ErrorInfo.MOK.getValue()) {
                log.error("引擎初始化失败，错误码: {}", errorCode);
                throw new RuntimeException("人脸引擎初始化失败");
            }
            
            log.info("人脸识别引擎初始化成功");
            
        } catch (Exception e) {
            log.error("人脸引擎初始化异常", e);
            throw new RuntimeException("人脸引擎初始化异常", e);
        }
    }

    /**
     * 获取实际的库路径
     */
    private String getActualLibPath() {
        String configPath = config.getLibPath();
        
        // 如果配置的是绝对路径且存在，直接返回
        File configDir = new File(configPath);
        if (configDir.isAbsolute() && configDir.exists()) {
            return configPath;
        }
        
        // 尝试从项目根目录开始查找
        String userDir = System.getProperty("user.dir");
        String[] possiblePaths = {
            // 相对于当前工作目录
            userDir + File.separator + "arcsoft_lib",
            // 相对于项目根目录
            userDir + File.separator + ".." + File.separator + ".." + File.separator + "arcsoft_lib",
            // 相对于warm-star目录
            userDir.replace("warm-module" + File.separator + "warm-user", "") + "arcsoft_lib",
            // 配置的原始路径
            configPath
        };
        
        for (String path : possiblePaths) {
            File dir = new File(path);
            if (dir.exists() && dir.isDirectory()) {
                // 检查是否包含必要的DLL文件
                File[] dlls = dir.listFiles((d, name) -> name.endsWith(".dll"));
                if (dlls != null && dlls.length > 0) {
                    log.info("找到库目录: {}", path);
                    return path;
                }
            }
        }
        
        log.warn("未找到有效的库目录，使用配置路径: {}", configPath);
        return configPath;
    }

    /**
     * 销毁引擎
     */
    @PreDestroy
    public void destroy() {
        if (faceEngine != null) {
            int errorCode = faceEngine.unInit();
            if (errorCode != ErrorInfo.MOK.getValue()) {
                log.error("引擎销毁失败，错误码: {}", errorCode);
            } else {
                log.info("人脸识别引擎销毁成功");
            }
        }
    }

    /**
     * 从图片文件中提取人脸特征
     * 
     * @param imageFile 图片文件
     * @return 人脸特征数据
     */
    public byte[] extractFaceFeature(File imageFile) {
        try {
            BufferedImage bufferedImage = ImageIO.read(imageFile);
            return extractFaceFeature(bufferedImage);
        } catch (IOException e) {
            log.error("读取图片文件失败", e);
            throw new RuntimeException("读取图片文件失败", e);
        }
    }

    /**
     * 从字节数组中提取人脸特征
     * 
     * @param imageBytes 图片字节数组
     * @return 人脸特征数据
     */
    public byte[] extractFaceFeature(byte[] imageBytes) {
        try {
            BufferedImage bufferedImage = ImageIO.read(new ByteArrayInputStream(imageBytes));
            return extractFaceFeature(bufferedImage);
        } catch (IOException e) {
            log.error("读取图片字节数组失败", e);
            throw new RuntimeException("读取图片字节数组失败", e);
        }
    }

    /**
     * 从BufferedImage中提取人脸特征
     * 
     * @param bufferedImage 图片对象
     * @return 人脸特征数据
     */
    public byte[] extractFaceFeature(BufferedImage bufferedImage) {
        if (bufferedImage == null) {
            throw new IllegalArgumentException("图片不能为空");
        }

        try {
            // 将BufferedImage转换为ImageInfo
            int width = bufferedImage.getWidth();
            int height = bufferedImage.getHeight();
            byte[] imageData = new byte[width * height * 3];
            
            // 转换RGB数据
            int index = 0;
            for (int y = 0; y < height; y++) {
                for (int x = 0; x < width; x++) {
                    int rgb = bufferedImage.getRGB(x, y);
                    imageData[index++] = (byte) (rgb >> 16); // B
                    imageData[index++] = (byte) (rgb >> 8);  // G
                    imageData[index++] = (byte) rgb;         // R
                }
            }
            
            // 人脸检测
            List<FaceInfo> faceInfoList = new ArrayList<>();
            int errorCode = faceEngine.detectFaces(imageData, width, height, ImageFormat.CP_PAF_BGR24, faceInfoList);
                    
            if (errorCode != ErrorInfo.MOK.getValue()) {
                log.error("人脸检测失败，错误码: {}", errorCode);
                throw new RuntimeException("人脸检测失败");
            }
            
            if (faceInfoList.isEmpty()) {
                throw new RuntimeException("未检测到人脸");
            }
            
            if (faceInfoList.size() > 1) {
                throw new RuntimeException("检测到多张人脸，请确保图片中只有一张人脸");
            }
            
            FaceInfo faceInfo = faceInfoList.get(0);
            
            // 提取人脸特征
            com.arcsoft.face.FaceFeature faceFeature = new com.arcsoft.face.FaceFeature();
            errorCode = faceEngine.extractFaceFeature(imageData, width, height, ImageFormat.CP_PAF_BGR24, faceInfo, faceFeature);
                    
            if (errorCode != ErrorInfo.MOK.getValue()) {
                log.error("人脸特征提取失败，错误码: {}", errorCode);
                throw new RuntimeException("人脸特征提取失败");
            }
            
            return faceFeature.getFeatureData();
            
        } catch (Exception e) {
            log.error("提取人脸特征异常", e);
            throw new RuntimeException("提取人脸特征异常", e);
        }
    }

    /**
     * 人脸特征对比
     * 
     * @param feature1 特征1
     * @param feature2 特征2
     * @return 相似度 (0-1之间，越接近1越相似)
     */
    public float compareFaceFeature(byte[] feature1, byte[] feature2) {
        if (feature1 == null || feature2 == null) {
            throw new IllegalArgumentException("人脸特征不能为空");
        }
        
        try {
            // 创建FaceFeature对象
            com.arcsoft.face.FaceFeature faceFeature1 = new com.arcsoft.face.FaceFeature();
            faceFeature1.setFeatureData(feature1);
            
            com.arcsoft.face.FaceFeature faceFeature2 = new com.arcsoft.face.FaceFeature();
            faceFeature2.setFeatureData(feature2);
            
            FaceSimilar faceSimilar = new FaceSimilar();
            int errorCode = faceEngine.compareFaceFeature(faceFeature1, faceFeature2, faceSimilar);
            
            if (errorCode != ErrorInfo.MOK.getValue()) {
                log.error("人脸特征对比失败，错误码: {}", errorCode);
                throw new RuntimeException("人脸特征对比失败");
            }
            
            return faceSimilar.getScore();
            
        } catch (Exception e) {
            log.error("人脸特征对比异常", e);
            throw new RuntimeException("人脸特征对比异常", e);
        }
    }

    /**
     * 判断两个人脸特征是否匹配
     * 
     * @param feature1 特征1
     * @param feature2 特征2
     * @return true：匹配，false：不匹配
     */
    public boolean isFaceMatch(byte[] feature1, byte[] feature2) {
        float similar = compareFaceFeature(feature1, feature2);
        return similar >= config.getSimilarThreshold();
    }
}
